Creating a Derived Media Handler Component
This section provides an example of creating a derived media handler component. The functional interface that your derived media handler component must support is described in "Derived Media Handler Components Reference" beginning on page 10-13.Before reading this section, you should be familiar with how to create components. See the chapter "Component Manager" in Inside Macintosh: More Macintosh Toolbox for a complete discussion of components--how to use them and how to create them.
Apple has defined a component type value for media handler components. All components of this type have the same type value. You can use the following constant to specify this component type:
#define MediaHandlerType 'mhlr' /* media handler */Apple has defined a functional interface for derived media handler components. For information about the functions that your component must support, see "Derived Media Handler Components Reference" beginning on page 10-13. You can use the following constants to refer to the request codes for each of the functions that your component must support:
enum { kMediaInitializeSelect = 0x501, /* MediaInitialize */ kMediaSetHandlerCapabilitiesSelect = 0x502, /* MediaSetHandlerCapabilities */ kMediaIdleSelect = 0x503, /* MediaIdle */ kMediaGetMediaInfoSelect = 0x504, /* MediaGetMediaInfo */ kMediaPutMediaInfoSelect = 0x505, /* MediaPutMediaInfo */ kMediaSetActiveSelect = 0x506, /* MediaSetActive */ kMediaSetRateSelect = 0x507, /* MediaSetRate */ kMediaGGetStatusSelect = 0x508, /* MediaGGetStatus */ kMediaTrackEditedSelect = 0x509, /* MediaTrackEdited */ kMediaSetMediaTimeScaleSelect = 0x50A, /* MediaSetMediaTimeScale */ kMediaSetMovieTimeScaleSelect = 0x50B, /* MediaSetMovieTimeScale */ kMediaSetGWorldSelect = 0x50C, /* MediaSetGWorld */ kMediaSetDimensionsSelect = 0x50D, /* MediaSetDimensions */ kMediaSetClipSelect = 0x50E, /* MediaSetClip */ kMediaSetMatrixSelect = 0x50F, /* MediaSetMatrix */ kMediaGetTrackOpaqueSelect = 0x510, /* MediaGetTrackOpaque */ kMediaSetGraphicsModeSelect = 0x511, /* MediaSetGraphicsMode */ kMediaGetGraphicsModeSelect = 0x512, /* MediaGetGraphicsMode */ kMediaGSetVolumeSelect = 0x513, /* MediaGSetVolume */ kMediaSetSoundBalanceSelect = 0x514, /* MediaSetSoundBalance */ kMediaGetSoundBalanceSelect = 0x515, /* MediaGetSoundBalance */ kMediaGetNextBoundsChangeSelect = 0x516, /* MediaGetNextBoundsChange */ kMediaGetSrcRgnSelect = 0x517, /* MediaGetSrcRgn */ kMediaPrerollSelect = 0x518, /* MediaPreroll */ kMediaSampleDescriptionChangedSelect = 0x519, /* MediaSampleDescriptionChanged */ kMediaHasCharacteristicSelect = 0x51A /* MediaHasCharacteristic */ };Component Flags for Derived Media Handlers
The Component Manager allows you to specify information about your component's capabilities in thecomponentFlags
field of the component description record. You must set this component flag to 1 in the component description that is associated with your derived media handler:
mediaHandlerFlagBaseClient
- Indicates that your component is derived from another component. Setting this flag to 1 tells the Component Manager that your component is a client of the base media handler.
Request Processing
Because your derived media handler is based on the base media handler component, you avoid many of the details involved in creating a media handler. However, your derived media handler must observe a few rules when processing service requests. These rules are as follows:
- When you receive an open request from the Component Manager, in addition to the other processing you perform on your own behalf, you must also open a connection to the base media handler component. You should save the component instance that is returned by the Component Manager so that your media handler can use the services of the base media handler.
- The base media handler has a component type of
MediaHandlerType
(which is set to'mhlr'
) and a component subtype ofBaseMediaType
(which is set to'gnrc'
). You can use these values with the Component Manager'sOpenDefaultComponent
function to open a connection to the base media handler.- At this time, you must also tell the base media handler that your handler is derived from it. Use the Component Manager's
OpenComponent
function to create a component instance of your media handler as a descendant of the base media handler. After calling that function, you should send thekComponentSetTargetSelect
request to the base media handler, so that it knows your media handler is derived from it. Use the Component Manager'sComponentSetTarget
function to send a target request.- When you receive a close request from the Component Manager, be sure to close your handler's connection to the base media handler component. Use the Component Manager's
CloseComponent
function.- Your derived media handler must support the target request, so that your component can be used by other media handlers.
- Be sure to pass all unsupported service requests to the base media handler component. Use the Component Manager's
DelegateComponentCall
function to pass these requests to the base media handler.- If your media handler component competes for potentially scarce system resources, your component should release those resources when you aren't using them. For example, if you are creating a media handler that uses sound, you might use sound channels. Because there are a limited number of sound channels available, your component should free its channels whenever your media is not playing or has been stopped. You can reallocate the channels when you start playing or your component's
MediaPreroll
function is called.
A Sample Derived Media Handler Component
This section supplies a sample program that implements a derived media handler component for PICT images.Implementing the Required Component Functions
Listing 10-1 supplies the component dispatchers for the media handler component for PICT images together with the required functions.Listing 10-1 Implementing the required functions
typedef struct { ComponentInstance self; ComponentInstance parent; ComponentInstance delegateComponent; Fixed width; Fixed height; MatrixRecord matrix; Media media; Track track; } PictGlobalsRecord, *PictGlobals; pascal ComponentResult PictMediaDispatch (ComponentParameters *params, Handle storage) { OSErr err = badComponentSelector; ComponentFunction componentProc = 0; switch (params->what) { case kComponentOpenSelect: componentProc = PictOpen; break; case kComponentCloseSelect: componentProc = PictClose; break; case kComponentCanDoSelect: componentProc = PictCanDo; break; case kComponentVersionSelect: componentProc = PictVersion; break; case kComponentTargetSelect: componentProc = PictVersion; break; case kMediaInitializeSelect: componentProc = PictInitialize; break; case kMediaIdleSelect: componentProc = PictIdle; break; case kMediaSetDimensionsSelect: componentProc = PictSetDimensions; break; case kMediaSetMatrixSelect: componentProc = PictSetMatrix; break; } if (componentProc) err = CallComponentFunctionWithStorage (storage, params, componentProc); else err = DelegateComponentCall (params, ((PictGlobals) storage)->delegateComponent); return err; } pascal ComponentResult PictCanDo (PictGlobals globals, short ftnNumber) { switch (ftnNumber) { case kComponentOpenSelect: case kComponentCloseSelect: case kComponentCanDoSelect: case kComponentVersionSelect: case kComponentTargetSelect: case kMediaInitializeSelect: case kMediaIdleSelect: case kMediaSetDimensionsSelect: case kMediaSetMatrixSelect: return true; default: return ComponentFunctionImplemented (globals->delegateComponent, ftnNumber); } } pascal ComponentResult PictVersion (PictGlobals globals) { return 0x00020001; } pascal ComponentResult PictOpen(PictGlobals globals, ComponentInstance self) { OSErr err; /* allocate storage */ globals = (PictGlobals)NewPtrClear(sizeof(PictGlobalsRecord)); if (err = MemError()) return err; SetComponentInstanceStorage(self, (Handle)globals); globals->self = self; globals->parent = self; /* find a base media handler to serve as a delegate */ globals->delegateComponent = OpenDefaultComponent (MediaHandlerType, BaseMediaType); if (globals->delegateComponent) PictTarget(globals, self); /* set up the calling chain */ else { DisposePtr((Ptr)globals); err = cantOpenHandler; } return err; } pascal ComponentResult PictClose (PictGlobals globals, ComponentInstance self) { if (globals) { if (globals->delegateComponent) CloseComponent(globals->delegateComponent); DisposePtr((Ptr)globals); } return noErr; } pascal ComponentResult PictTarget(PictGlobals store, ComponentInstance parentComponent) { /* remember who is at the top of your calling chain */ store->parent = parentComponent; /* and inform your delegate component of the change */ ComponentSetTarget(store->delegateComponent, parentComponent); return noErr; }Initializing a Derived Media Handler Component
The derived media handler component is initialized by the Movie Toolbox's calling of theMediaInitialize
function (described on page 10-17). You should then report the derived media handler capabilities to the base media handler before the Movie Toolbox starts working with your media by calling theMediaSetHandlerCapabilities
function (described on page 10-36) from yourMediaInitialize
function.Listing 10-2 is the initialization function for a derived media handler. The
PictInitialize
function stores the initial height, width, track movie matrix, media, and track of the derived media handler component. FromPictInitialize
, theMediaSetHandlerCapabilities
function is called to inform the base media handler of its existence and features.Listing 10-2 Initializing a derived media handler
pascal ComponentResult PictInitialize (PictGlobals store, GetMovieCompleteParams *gmc) { /* remember some useful parameters */ store->width = gmc->width; store->height = gmc->height; store->matrix = gmc->trackMovieMatrix; store->media = gmc->theMedia; store->track = gmc->theTrack; /* tell the base media handler about your derived media handler */ MediaSetHandlerCapabilities(store->delegateComponent, handlerHasSpatial, handlerHasSpatial); return noErr; }Drawing the Media Sample
The Movie Toolbox provides processing time to your derived media handler to display samples by calling theMediaIdle
function (described on page 10-18). Your media handler may use this time to play its media sample. The code in Listing 10-3 allows the derived media handler component to draw the current media sample (in this case, a PICT image).Listing 10-3 Drawing the media sample
pascal ComponentResult PictIdle (PictGlobals store, TimeValue atMediaTime, long flagsIn, long *flagsOut, const TimeValue *tr) { OSErr err; Rect r; Handle sample = NewHandle (0); if (err = MemError()) goto bail; /* get the current sample */ err = GetMediaSample (store->media, sample, 0, nil, atMediaTime, nil, 0, 0, 0, 0, 0, 0); if (err) goto bail; /* draw it using the current matrix */ SetRect (&r, 0, 0, FixRound (store->width), FixRound (store->height)); TransformRect (&store->matrix, &r, nil); EraseRect (&r); DrawPicture ((PicHandle)sample, &r); bail: DisposeHandle (sample); *flagsOut |= mDidDraw; /* let Movie Toolbox know you drew something */ return err; } pascal ComponentResult PictSetDimensions (PictGlobals store, Fixed width, Fixed height) { /* remember the new track */ store->width = width; store->height = height; return noErr; } pascal ComponentResult PictSetMatrix (PictGlobals store, MatrixRecord *trackMovieMatrix) { /* remember the new display matrix */ store->matrix = *trackMovieMatrix; return noErr; }
Subtopics
- Component Flags for Derived Media Handlers
- Request Processing
- A Sample Derived Media Handler Component
- Implementing the Required Component Functions
- Initializing a Derived Media Handler Component
- Drawing the Media Sample
Main | Top of Section | What's New | Apple Computer, Inc. | Find It | Feedback | Help